package com.doophan.optimal.path;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;


public class App {
    public static void main(String[] args) throws Exception {
        init();
        // 已知bug: key循环递归栈溢出问题
        LinkedHashSet<String> optimalPath = optimalPath("知春路", "宣武门");
        printPath(optimalPath);
//        int res = countFileLines();
//        System.out.println(res);
    }
    
    // 跟踪递归调用栈,保证不循环递归
    private static List<String[]> stackTrace = new ArrayList<>();
    
    /**
     * 求最优路径
     * 1.起点A B在同一线路
     * 2.起点A B在不同线路
     *  2.1 lineA lineB有交点
     *  2.2 lineA lineB无交点,化为求lineA枢纽与lineB枢纽的最优路径,递归处理
     */
    private static LinkedHashSet<String> optimalPath(String start, String end) {
        LinkedHashSet<String> res = new LinkedHashSet<>();
    	
        // 1.起止点属同一线路
        // 两点之间如果存在线路
        Map<String, LinkedHashSet<String>> lines = getLines(start, end);
        if(lines != null && lines.size() > 0) {
//        	for(LinkedHashSet<String> line : lines) {
//        		LinkedHashSet<String> path = getPath(line, start, end);
//	            res = res.size() == 0 ? path : nearer(path, res);
//        	}
        	
        	for(Map.Entry<String, LinkedHashSet<String>> entry : lines.entrySet()) {
        		LinkedHashSet<String> path = getPath(entry.getValue(), start, end);
	            res = res.size() == 0 ? path : nearer(path, res);
        	}
        	return res;
        // 2.起止点属于不同线路
        } else {
            List<LinkedHashSet<String>> linesStart = getLines(start);
            List<LinkedHashSet<String>> linesEnd = getLines(end);
            for(LinkedHashSet<String> lineStart : linesStart) {
                for(LinkedHashSet<String> lineEnd : linesEnd) {
                    List<String> commons = commons(lineStart, lineEnd);
                    // 求两条线路的所有交点,注意交点不只一条,如U形及环线
                    if(commons != null && commons.size() > 0) {
                        for (String common : commons) {
                            LinkedHashSet<String> path = new LinkedHashSet<>();
                            LinkedHashSet<String> pathStart = getPath(lineStart, start, common);
                            LinkedHashSet<String> pathEnd = getPath(lineEnd, common, end);
                            path.addAll(pathStart);
                            path.addAll(pathEnd);
                            // 每次循环保留路径较短者,即最终求得最短路径
                            res = res.size() == 0 ? path : nearer(path, res);
                        }
                    }
                    else {
                        // 求两条线的所有枢纽点
                        Set<String> lineStartKeys = getKeyPoint(lineStart);
                        Set<String> lineEndKeys = getKeyPoint(lineEnd);
                        // 对两条线路枢纽点进行遍历
                        for (String keyStart : lineStartKeys) {
                            for (String keyEnd : lineEndKeys) {
                            	if(isInStackTrace(start, end)) {
                                	continue;
                                } 
                                
                                String[] stack = new String[2];
                            	stack[0] = start;
                            	stack[1] = end;
                            	stackTrace.add(stack);
                                LinkedHashSet<String> path = new LinkedHashSet<>();
                                // 保证递归调用排除掉
                                if(start.equals(keyStart) || end.equals(keyEnd)) {
                                	continue;
                                }
                                // 求开始节点到其所在线路的枢纽点路径
                                LinkedHashSet<String> pathStartToKey = getPath(lineStart, start, keyStart);
                                path.addAll(pathStartToKey);
                                
                                LinkedHashSet<String> pathKeyToKey = optimalPath(keyStart, keyEnd);
                                path.addAll(pathKeyToKey);
                                
                                // 求结束节点到其所在线路的枢纽点路径
                                LinkedHashSet<String> pathKeyToEnd = getPath(lineEnd, keyEnd, end);
                                path.addAll(pathKeyToEnd);
                                
                                // 保留较短路径
                                res = res.size() == 0 ? path : nearer(path, res);
                                
                            }
                        }
                    }
                }
            }
            return res;
        }
    }
    
    /**
     * 判断递归参数是否已在调用栈中
     * @param start
     * @param end
     * @return
     */
    private static boolean isInStackTrace(String start, String end) {
    	boolean res = false;
    	for(String[] stack : stackTrace) {
    		if(start.equals(stack[0]) && end.equals(stack[1])) {
    			res = true;
    			break;
    		}
    	} 
    	return res;
    }

    /**
     * 求某条线路的所有枢纽点
     * 同样简单处理,假设交点只有一条
     * @param line
     * @return
     */
     private static Set<String> getKeyPoint(Set<String> line) {
        Set<String> keys = new HashSet<>();
        Set<String> l;
        for(Map.Entry<String, LinkedHashSet<String>> entry : tu.entrySet()) {
            l = entry.getValue();
            if(l.equals(line)) {
                continue;
            }
            List<String> commons = commons(line, l);
            if(commons != null && commons.size() > 0) {
                keys.addAll(commons);
            }
        }
        return keys;
    }

    /**
     * 获取某个点所在的线路
     * 1.简单情况,点只属于一个线路
     * 2.较复杂情况,点属于两个线路
     * 3.点属于3个以上线路的情况...
     * @param point
     * @return
     */
    private static List<LinkedHashSet<String>> getLines(String point) {
        List<LinkedHashSet<String>> res = new ArrayList<>();
        for(Map.Entry<String, LinkedHashSet<String>> entry : tu.entrySet()) {
            LinkedHashSet<String> line = entry.getValue();
            if(belongs(point, line)) {
                res.add(line);
            }
        }
        return res;
     }

    /**
     * 求两条线路的交点
     * 考虑简单情况,两条线路仅有一个交点的情况
     * @return
     */
    private static List<String> commons(Set<String> line1, Set<String> line2) {
        List<String> commons = new ArrayList<>();
        Iterator<String> it = line1.iterator();
        while(it.hasNext()) {
            String ele = it.next();
            if(belongs(ele, line2)) {
                commons.add(ele);
            }
        }
        return commons;
    }

    /**
     * 判断某个点是否属于某个线路
     * @param point
     * @param line
     * @return
     */
    private static boolean belongs(String point, Set<String> line) {
        boolean res = false;
        Iterator<String> it = line.iterator();
        while(it.hasNext()) {
            String ele = it.next();
            if(ele.equals(point)) {
                res = true;
                break;
            }
        }
        return res;
    }

    /**
     * 判断起点和终点是否在同一线路上
     * 这里只考虑线路唯一的简单情况
     * 如果是,返回该线路
     * 如果否,返回null
     * @return
     */
    private static Map<String, LinkedHashSet<String>> getLines(String start, String end) {
        Map<String, LinkedHashSet<String>> res = new HashMap<>();
        // 对所有集合进行循环判定是否在同一线路
        for(Map.Entry<String, LinkedHashSet<String>> entry : tu.entrySet()) {
        	LinkedHashSet<String> set = entry.getValue();
            if(belongs(set, start, end)) {
            	res.put(entry.getKey(), set);
            }
        }
        return res;
    }

    /**
     * 判断起点和终点是否同属于某一线路
     * @return
     */
    private static boolean belongs(LinkedHashSet<String> line, String start, String end) {
        byte res = 0;
        Iterator<String> it = line.iterator();
        String s;
        while(it.hasNext()) {
            s = it.next();
            if(s.equals(start)) {
                res ++;
            }
            if(s.equals(end)) {
                res ++;
            }
        }
        return res == 2;
    }

    /**
     * 获取线路图
     * 如果是环线,则首尾节点可以联通
     */
    private static LinkedHashSet<String> getPath(LinkedHashSet<String> path, String start, String end) {
        LinkedHashSet<String> res;
        // 如果是环线,两种方案
        // 环线有无方向问题
        if(isCircle(path)) {
            // 这里有点绕
            String first = getFirst(path);
            String last = getLast(path);
            // 如果起始节点在结束节点前
            if(pre(path, start, end)) {
                // 顺时针
                LinkedHashSet<String> resClock = getDirectPath(path, start, end);
                LinkedHashSet<String> resAntiClock = new LinkedHashSet<>();
                // 逆时针
                LinkedHashSet<String> startToFirst = getDirectPath(path, start, first);
                resAntiClock.addAll(startToFirst);
                LinkedHashSet<String> lastToEnd = getDirectPath(path, last, end);
                resAntiClock.addAll(lastToEnd);
                res = nearer(resClock, resAntiClock);
            // 如果起始节点在结束节点后
            } else {
                // 顺时针
                LinkedHashSet<String> resClock = new LinkedHashSet<>();
                LinkedHashSet<String> startToLast = getDirectPath(path, start, last);
                resClock.addAll(startToLast);
                LinkedHashSet<String> firstToEnd = new LinkedHashSet<>();
                resClock.addAll(firstToEnd);
                // 逆时针
                LinkedHashSet<String> resAntiClock = getDirectPath(path, start, end);
                res = nearer(resClock, resAntiClock);
            }
        } else {
            res = getDirectPath(path, start, end);
        }
        return res;
    }

    /**
     * 返回两个路径长度较小的那个
     * @return
     */
    private static LinkedHashSet<String> nearer(LinkedHashSet<String> one, LinkedHashSet<String> two) {
        return one.size() <= two.size() ? one : two;
    }

    /**
     * 获取首节点
     * @param path
     * @return
     */
    private static String getFirst(LinkedHashSet<String> path) {
        return path.stream().findFirst().get();
    }

    /**
     * 获取尾节点
     * @param path
     * @return
     */
    private static String getLast(LinkedHashSet<String> path) {
        return getFirst(reverse(path));
    }

    /**
     * 判断pointA是否在pointB上游
     * @param path
     * @param pointA
     * @param pointB
     * @return
     */
    private static boolean pre(LinkedHashSet<String> path, String pointA, String pointB) {
        boolean res = true;
        for(String ele : path) {
            // pointA先出现
            if(ele.equals(pointA)) {
                res = true;
                break;
            }
            // pointB先出现
            if(ele.equals(pointB)) {
                res = false;
                break;
            }
        }
        return res;
    }

    /**
     * 路径是否是环线
     * @param path
     * @return
     */
    private static boolean isCircle(LinkedHashSet<String> path) {
        if(path.equals(line2) || path.equals(line10)) {
            return true;
        }
        return false;
    }

    /**
     * 打印直线路径
     * @param path
     * @param start
     * @param end
     * @return
     */
    private static LinkedHashSet getDirectPath(LinkedHashSet<String> path, String start, String end) {
        LinkedHashSet<String> res = new LinkedHashSet<>();
        // 如果开始结束节点相同,返回单个元素的节点
        if(start.equals(end)) {
            res.add(start);
            return res;
        }
        boolean reverseFlag = ifReverse(path, start, end);
        if (reverseFlag) {
            path = reverse(path);
        }
        Iterator<String> it = path.iterator();
        boolean flag = false;
        while (it.hasNext()) {
            String ele = it.next();
            if (ele.equals(start)) {
                flag = true;
            }

            if (flag) {
                res.add(ele);
            }

            if (ele.equals(end)) {
                flag = false;
            }
        }
        return res;
    }

    /**
     * 把LinkedHashSet元素逆序排列
     * @return
     */
    private static LinkedHashSet<String> reverse(LinkedHashSet<String> set) {
        LinkedHashSet<String> newSet = new LinkedHashSet<>();
        LinkedList<String> list = new LinkedList<>(set);
        Iterator<String> itr = list.descendingIterator();
        while(itr.hasNext()) {
            String ele = itr.next();
            newSet.add(ele);
        }
        return newSet;
    }

    /**
     * 根据起点和终点判断线路是正序还是逆序
     * @return
     */
    private static boolean ifReverse(Set<String> line, String start, String end) {
       byte flag = 0;
       Iterator<String> it = line.iterator();
       while(it.hasNext()) {
           String ele = it.next();
           if(ele.equals(start)) {
               flag = 1;
               break;
           }
           // 如果end先于start出现,说明是逆序
           if(ele.equals(end)) {
               flag = 2;
               break;
           }
       }
       return flag == 2;
    }

    /**
     * 打印总线路
     * @param path
     */
    private static void printPath(LinkedHashSet<String> path) {
        StringBuffer sb = new StringBuffer();
        for(String ele : path) {
            sb.append(ele).append(" -> ");
        }
        if(sb.length() > 0) {
            System.out.println(sb.substring(0, sb.length() - 4));
        }
    }
    
    /**
     * 统计文件行数
     * @return
     * @throws Exception
     */
     private static int countFileLines() throws Exception {
    	int res = 0;
    	BufferedReader br = new BufferedReader(new FileReader(new File("error.txt")));
    	String line;
    	while((line = br.readLine()) != null) {
    		res++;
    	}
    	return res;
    }


    private static Map<String, LinkedHashSet<String>> tu = new HashMap<>();
    /** 昌平线 */
    private static LinkedHashSet lineChangPing = new LinkedHashSet();
    /** 13号线 */
    private static LinkedHashSet line13 = new LinkedHashSet();
    /** 8号线 */
    private static LinkedHashSet line8 = new LinkedHashSet();
    /** 5号线 */
    private static LinkedHashSet line5 = new LinkedHashSet();
    /** 1号线 */
    private static LinkedHashSet line1 = new LinkedHashSet();
    /** 2号线 */
    private static LinkedHashSet line2 = new LinkedHashSet();
    /** 4号线 */
    private static LinkedHashSet line4 = new LinkedHashSet();
    /** 6号线 */
    private static LinkedHashSet line6 = new LinkedHashSet();
    /** 7号线 */
    private static LinkedHashSet line7 = new LinkedHashSet();
    /** 8号线南段 */
    private static LinkedHashSet line8South = new LinkedHashSet();
    /** 9号线 */
    private static LinkedHashSet line9 = new LinkedHashSet();
    /** 10号线 */
    private static LinkedHashSet line10 = new LinkedHashSet();
    /** 新机场线 */
    private static LinkedHashSet lineNewAirport = new LinkedHashSet();
    /** 14号线西段 */
    private static LinkedHashSet line14West = new LinkedHashSet();
    /** 14号线东段 */
    private static LinkedHashSet line14East = new LinkedHashSet();
    /** 15号线 */
    private static LinkedHashSet line15 = new LinkedHashSet();
    /** 16号线 */
    private static LinkedHashSet line16 = new LinkedHashSet();
    /** 八通线 */
    private static LinkedHashSet lineBaTong = new LinkedHashSet();
    /** 亦庄线 */
    private static LinkedHashSet yiZhuang = new LinkedHashSet();
    /** 房山线 */
    private static LinkedHashSet fangShan = new LinkedHashSet();
    /** 机场线 */
    private static LinkedHashSet jiChang = new LinkedHashSet();
    /** s1线 */
    private static LinkedHashSet s1 = new LinkedHashSet();
    /** 燕房线 */
    private static LinkedHashSet yanFang = new LinkedHashSet();
    /** 西郊线 */
    private static LinkedHashSet xiJiao = new LinkedHashSet();

    /**
     * 线路数据初始化
     */
    private static void init() {
        // 初始化昌平线
        initLineChangPing();
        // 初始化13号线
        initLine13();
        // 初始化8号线
        initLine8();
        // 初始化5号线
        initLine5();
        // 初始化1号线
        initLine1();
        // 初始化4号线
        initLine4();
        // 初始化2号线
        initLine2();
        // 初始化6号线
        initLine6();
        // 初始化7号线
        initLine7();
        // 初始化8号线-南段
        initLine8South();
        // 初始化9号线
        initLine9();
        // 初始化10号线
        initLine10();
        // 初始化新机场线
        initLineNewAirport();
        // 初始化14号线-西段
        initLine14West();
        // 初始化14号线-东段
        initLine14East();
        // 各条线路添加到线路图
        tu.put("昌平线", lineChangPing);
        tu.put("13号线", line13);
        tu.put("8号线", line8);
        tu.put("5号线", line5);
        tu.put("1号线", line1);
        tu.put("4号线", line4);
        tu.put("2号线", line2);
        tu.put("6号线", line6);
        tu.put("7号线", line7);
        tu.put("8号线-南段", line8South);
        tu.put("9号线", line9);
        tu.put("10号线", line10);
        tu.put("新机场线", lineNewAirport);
        tu.put("14号线-西段", line14West);
        tu.put("14号线-东段", line14East);
        tu.put("15号线", line15);
    }

    /**
     * 5号线数据初始化
     */
    private static void initLine5() {
        line8.addAll(Arrays.asList(
                "天通苑北",
                "天通苑",
                "天通苑南",
                "立水桥",
                "立水桥南",
                "北苑路北",
                "惠新西街北口",
                "惠新西街南口",
                "和平西桥",
                "和平里北街",
                "雍和宫",
                "北新桥",
                "张自忠路",
                "东四",
                "灯市口",
                "东单",
                "磁器口",
                "天坛东门",
                "蒲黄榆",
                "刘家窑",
                "宋家庄"
        ));
    }

    /**
     * 昌平线数据初始化
     */
    private static void initLineChangPing() {
        line8.addAll(Arrays.asList(
                "昌平西山口",
                "十三陵景区",
                "昌平",
                "昌平东关",
                "北邵洼",
                "南邵",
                "沙河高教园",
                "沙河",
                "巩华城",
                "朱辛庄",
                "生命科学园",
                "西二旗"
        ));
    }

    /**
     * 13号线数据初始化
     */
    private static void initLine13() {
        line13.addAll(Arrays.asList(
                "西直门",
                "大钟寺",
                "知春路",
                "五道口",
                "上地",
                "清河站",
                "西二旗",
                "龙泽",
                "回龙观",
                "霍营",
                "立水桥",
                "北苑",
                "望京西",
                "芍药居",
                "光熙门",
                "柳芳",
                "东直门"
        ));
    }

    /**
     * 8号线数据初始化
     */
    private static void initLine8() {
        line8.addAll(Arrays.asList(
                "朱辛庄",
                "育知路",
                "平西府",
                "回龙观东大街",
                "霍营",
                "育新",
                "西小口",
                "永泰庄",
                "林萃桥",
                "森林公园南门",
                "奥林匹克公园",
                "奥体中心",
                "北土城",
                "安华桥",
                "安德里北街",
                "鼓楼大街",
                "什刹海",
                "南锣鼓巷",
                "中国美术馆"
        ));
    }

    /**
     * 1号线数据初始化
     */
    private static void initLine1() {
        line1.addAll(Arrays.asList(
                "古城",
                "八角游乐园",
                "八宝山",
                "玉泉路",
                "五棵松",
                "万寿路",
                "公主坟",
                "军事博物馆",
                "木樨地",
                "南礼士路",
                "复兴门",
                "西单",
                "天安门西",
                "天安门东",
                "王府井",
                "东单",
                "建国门",
                "永安里",
                "国贸",
                "大望路",
                "四惠",
                "四惠东",
                "高碑店",
                "传媒大学",
                "双桥",
                "管庄",
                "八里桥",
                "通州北苑",
                "果园",
                "九棵树",
                "梨园",
                "临河里",
                "土桥",
                "花庄"
        ));
    }

    /**
     * 4号线数据初始化
     */
    private static void initLine4() {
        line4.addAll(Arrays.asList(
                "安和桥北",
                "北宫门",
                "西站",
                "圆明园",
                "北京大学东门",
                "中关村",
                "海淀黄庄",
                "人民大学",
                "魏公村",
                "国家图书馆",
                "动物园",
                "西直门",
                "新街口",
                "平安里",
                "西四",
                "灵境胡同",
                "西单",
                "宣武门",
                "菜市口",
                "陶然亭",
                "北京南站",
                "马家堡",
                "角门西",
                "公益西桥",
                "新宫",
                "西红门",
                "高米店北",
                "高米店南",
                "枣园",
                "清源路",
                "黄村西大街",
                "黄村火车站",
                "义和庄",
                "生物医药基地",
                "天宫院"
        ));
    }

    /**
     * 2号线数据初始化
     */
    private static void initLine2() {
        line2.addAll(Arrays.asList(
                "西直门",
                "积水潭",
                "鼓楼大街",
                "安定门",
                "雍和宫",
                "东直门",
                "东四十条",
                "朝阳门",
                "建国门",
                "北京站",
                "崇文门",
                "前门",
                "和平门",
                "宣武门",
                "长椿街",
                "复兴门",
                "阜成门",
                "车公庄"
        ));
    }

    /**
     * 6号线数据初始化
     */
    private static void initLine6() {
        line6.addAll(Arrays.asList(
                "全安桥",
                "杨庄",
                "西黄村",
                "廖公庄",
                "田村",
                "海淀五路居",
                "慈寿寺",
                "花园桥",
                "白石桥南",
                "车公庄西",
                "车公庄",
                "平安里",
                "北海北",
                "南锣鼓巷",
                "东四",
                "朝阳门",
                "东大桥",
                "呼家楼",
                "全台路",
                "十里堡",
                "青年路",
                "褡裢坡",
                "黄渠",
                "常营",
                "草房",
                "物资学院路",
                "通州北关",
                "北运河西",
                "北运河东",
                "郝家府",
                "东夏园",
                "潞城"
        ));
    }

    /**
     * 7号线数据初始化
     */
    private static void initLine7() {
        line7.addAll(Arrays.asList(
                "北京西站",
                "湾子",
                "达直营",
                "广安门内",
                "菜市口",
                "虎坊桥",
                "珠市口",
                "桥湾",
                "磁器口",
                "广渠门内",
                "广渠门外",
                "双井",
                "九龙山",
                "大郊亭",
                "百子湾",
                "化工",
                "南楼梓庄",
                "欢乐谷景区",
                "垡头",
                "双合",
                "焦化厂",
                "黄厂",
                "郎辛庄",
                "黑庄户",
                "万盛西",
                "万盛东",
                "群芳",
                "高楼金",
                "花庄"
        ));
    }

    /**
     * 8号线-南段数据初始化
     */
    private static void initLine8South() {
        line8South.addAll(Arrays.asList(
                "珠市口",
                "天桥",
                "永定门外",
                "木樨园",
                "海户屯",
                "大红门南",
                "和义",
                "东高地",
                "火箭万源",
                "五福堂",
                "德茂",
                "瀛海"
        ));
    }

    /**
     * 9号线数据初始化
     */
    private static void initLine9() {
        line9.addAll(Arrays.asList(
                "国家图书馆",
                "白石桥南",
                "白堆子",
                "军事博物馆",
                "北京西站",
                "六里桥东",
                "六里桥",
                "七里庄",
                "丰台东大街",
                "丰台南路",
                "科怡路",
                "郭公庄"
        ));
    }

    /**
     * 10号线数据初始化
     */
    private static void initLine10() {
        line10.addAll(Arrays.asList(
                "巴沟",
                "苏州街",
                "海淀黄庄",
                "知春里",
                "知春路",
                "西土城",
                "牡丹园",
                "健德门",
                "北土城",
                "安贞门",
                "惠新西街南口",
                "芍药居",
                "太阳宫",
                "三元桥",
                "亮马桥",
                "农业展览馆",
                "团结湖",
                "呼家楼",
                "金台夕照",
                "国贸",
                "双井",
                "劲松",
                "潘家园",
                "十里河",
                "分钟寺",
                "成寿寺",
                "宋家庄",
                "石榴庄",
                "大红门",
                "角门东",
                "角门西",
                "草桥",
                "纪家庙",
                "首经贸",
                "丰台站",
                "泥洼",
                "西局",
                "六里桥",
                "莲花桥",
                "公主坟",
                "西钓鱼台",
                "慈寿寺",
                "车道沟",
                "长春桥",
                "火器营"
        ));
    }

    /**
     * 新机场线数据初始化
     */
    private static void initLineNewAirport() {
        lineNewAirport.addAll(Arrays.asList(
                "草桥",
                "大兴新城",
                "大兴机场"
        ));
    }

    /**
     * 14号线-西段数据初始化
     */
    private static void initLine14West() {
        line14West.addAll(Arrays.asList(
                "张郭庄",
                "园博园",
                "大瓦窑",
                "郭庄子",
                "大井",
                "七里庄",
                "西局"
        ));
    }

    /**
     * 14号线-东段数据初始化
     */
    private static void initLine14East() {
        line14East.addAll(Arrays.asList(
                "善各庄",
                "来广营",
                "东湖渠",
                "阜通",
                "望京南",
                "将台",
                "东风北桥",
                "枣营",
                "朝阳公园",
                "金台路",
                "大望路",
                "九龙山",
                "平乐园",
                "北工大西门",
                "十里河",
                "方庄",
                "蒲黄榆",
                "景泰",
                "永定门外",
                "北京南站"
        ));
    }

    /**
     * 15号线数据初始化
     */
    private static void initLine15() {
        line15.addAll(Arrays.asList(
                "清华东路西口",
                "六道口",
                "北沙滩",
                "奥林匹克公园",
                "安立路",
                "大屯路东",
                "关庄",
                "望京西",
                "望京",
                "望京东",
                "崔各庄",
                "马泉营",
                "孙河",
                "国展",
                "花梨坎",
                "后沙峪",
                "南法信",
                "石门",
                "顺义",
                "俸伯"
        ));
    }
}